#include"element.h"
#include"double_linked_list.h"
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct double_linked_list * create_double_linked_list(struct element * elem){
    struct double_linked_list * lst=(struct double_linked_list *)malloc(sizeof(struct double_linked_list));
    lst->head=elem;
    lst->tail=elem;
    lst->head->next=lst->tail;
    lst->tail->prev=lst->head;
    return lst;
}
void append_tail_double_linked_list(struct double_linked_list * lst,struct element * elem){
    lst->tail->next=elem;
    elem->prev=lst->tail;
    lst->tail=elem;
    lst->tail->next=lst->head;
    lst->head->prev=lst->tail;
}

void append_head_double_linked_list(struct double_linked_list * lst,struct element * elem){
    lst->head->prev=elem;
    elem->next=lst->head;
    lst->head=elem;
    lst->tail->next=lst->head;
    lst->head->prev=lst->tail;
}
void print_list(struct double_linked_list * lst){
    if(lst==NULL) return;
    if(lst->head==NULL) return;
    struct element * current=lst->head;
    do{
        print_element(current);
        if(current==NULL) return;
        current=current->next;
    }while(current!=lst->head);
}   


void insert_double_linked_list(struct double_linked_list * lst,int index,struct element * elem){
    if(lst==NULL) return;
    if(lst->head==NULL) return;
    if(index==0) {
        append_head_double_linked_list(lst,elem);
        return ;
    }else{
        int i=0;
        struct element * current=lst->head;
        int status=0;
        while(current->next!=lst->head){
            current=current->next;
            i++;
            if((index-1)==i) {
                status=1;
                break;
            }
        }
        if(status==1){
            struct element * prev=current;
            struct element * next=current->next;
            elem->next=next;
            next->prev=elem;

            elem->prev=prev;
            prev->next=elem;

        }else{
            printf("index out of range\n");
            return ;
        }
    }
}

int search_data(struct double_linked_list * lst,char * data){
    int index=-1;
    if(lst==NULL) return index;
    else if(lst->head==NULL) return index;
    struct element * current_node=lst->head;
    int tmp=-1;
    do{
        tmp++;
        if(strcmp(current_node->data,data)==0){
            index=tmp;
            break;
        };
        current_node=current_node->next;
    }while(current_node!=lst->head);
    return index;
}

char * search_index(struct double_linked_list * lst,int index){
    if(index<0) return NULL;
    int tmp=0;
    struct element * current_node=lst->head;
    do{
        if(tmp==index)  return current_node->data;
        current_node=current_node->next;
        tmp++;
    }while(current_node!=lst->head);
    return NULL;
}

int remove_head(struct double_linked_list * lst){
    if(lst==NULL)  return -1;
    else if(lst->head==NULL) return -1;
    else if(lst->head==lst->tail){
        struct element * current_node=lst->head;
        lst->head=NULL;
        lst->tail=NULL;
        delete_element(current_node);
        current_node=NULL;
        return 0;
    }else{
        struct element * current_node=lst->head;
        struct element * previous_node=current_node->prev;
        struct element * next_node=current_node->next;
        previous_node->next=next_node;
        next_node->prev=previous_node;
        lst->head=next_node;
        lst->tail->prev=lst->head;
        return 0;
    }
}

int remove_tail(struct double_linked_list * lst){
    if(lst==NULL)  return -1;
    else if(lst->head==NULL) return -1;
    else if(lst->head==lst->tail){
        struct element * current_node=lst->head;
        lst->head=NULL;
        lst->tail=NULL;
        delete_element(current_node);
        current_node=NULL;
        return 0;
    }else{
        struct element * current_node=lst->tail;
        struct element * previous_node=current_node->prev;
        struct element * next_node=current_node->next;
        previous_node->next=next_node;
        next_node->prev=previous_node;
        lst->tail=previous_node;    
        lst->head->prev=lst->tail;
    }
}

int remove_data(struct double_linked_list * lst,char * data){
    if(lst==NULL)  return -1;
    else if(lst->head==NULL) return -1;
    else if(lst->head==lst->tail){
        struct element * current_node=lst->head;
        if(strcmp(current_node->data,data)==0)
            remove_head(lst);
        return 0;
    }else{
        struct element * current_node=lst->head;
        do{
            if(strcmp(current_node->data,data)==0){
               struct element * previous_node=current_node->prev;
               struct element * next_node=current_node->next;
               previous_node->next=next_node;
               next_node->prev=previous_node;
               if(current_node==lst->head){
                    lst->head=next_node;
               }else if(current_node==lst->tail){
                    lst->tail=previous_node;
               }
               delete_element(current_node);
               current_node=NULL;
               return 0;
            }
            current_node=current_node->next;
        }while(current_node!=lst->head);   
        return 0;
    }
}

int remove_index(struct double_linked_list * lst,int index){
    int tmp=0;
    if(lst==NULL)  return -1;
    else if(lst->head==NULL) return -1;
    else if(lst->head==lst->tail){
        struct element * current_node=lst->head;
        if(tmp==index)
            remove_head(lst);
        return 0;
    }else{
        struct element * current_node=lst->head;
        do{
            if(tmp==index){
               struct element * previous_node=current_node->prev;
               struct element * next_node=current_node->next;
               previous_node->next=next_node;
               next_node->prev=previous_node;
               if(current_node==lst->head){
                    lst->head=next_node;
               }else if(current_node==lst->tail){
                    lst->tail=previous_node;
               }
               delete_element(current_node);
               current_node=NULL;
               return 0;
            }
            current_node=current_node->next;
            tmp++;
        }while(current_node!=lst->head);   
        return 0;
    }
}

int delete_DLL(struct double_linked_list * lst){
    if(lst==NULL)  return -1;
    else if(lst->head==NULL) {
        free(lst);
        lst=NULL;
        return -1;    
    }else{
        do{
            remove_head(lst);
        }while(lst->head!=NULL);
        free(lst);
        lst=NULL;
        return 0;
    }
}